<template>
  <div>
    <slot></slot>
  </div>
</template>

<script>
export default {
  name: "EchartsGenerate",
  data() {
    return {
      instances: {},
      chartDom: null,
    };
  },
  props: {
    customOption: {
      type: Object,
      default: function () {
        return {};
      },
    },
    cultureMap: {
      type: Map,
      default: function () {
        return new Map();
      },
    },
    // 图表数据
    chartData: {
      type: Array,
      default: function () {
        return [];
      },
    },
    // 其他设置
    otherOption: {
      type: Object,
      default: function () {
        return {};
      },
    },
    // 图表id
    chartId: {
      type: String,
      default: null,
    },
    // 自动生成开关
    enableAuto: {
      type: Boolean,
      default: false,
    },

    // 坐标对应的 传入数据指定的键值
    nameDataKey: {
      type: String,
      default: "name",
    },
    // 数据对应的 传入数据指定的键值
    valueDataKey: {
      type: String,
      default: "value",
    },
    // 图表标题
    chartTitle: {
      type: String,
    },
  },
  created() {},
  mounted() {
    var _this = this;
    // 自动生成图表
    if (_this.enableAuto) {
      _this.generateChartById(
        _this.chartId,
        _this.chartData,
        _this.otherOption,
      );
    }
  },
  components: {},
  methods: {

    generateChartById(id, list, otherOption) {
      var _this = this;
      var preId = id;
      var suffixId = "";
      if (id.includes("_")) {
        preId = id.split("_")[0];
        suffixId = id.split("_")[1];
      }
      switch (preId) {
        case "chart-sample":
          _this.generateChart(
            id,
            "listData",
            "barOption",
            list
          );
          break;
      }
    },

    // 用于用户数据不需要处理
    // 直接传入数据源生成图表
    generateChartWithData(domRef, optionType, data) {
      const domElement = document.getElementById(domRef) || this.$refs[domRef];
      if (!domElement) {
        console.error(`Element with ID ${domRef} not found`);
        return;
      }

      let chartDom = this.initChartDom(domRef);
      if (chartDom) {
        let chart = this.getChart(domRef);
        // 存在表格的话先进行销毁
        if (chart) {
          chart.dispose();
        }
        let option = this.getDefaultOption(optionType, data);
        if (option && typeof option === "object") {
          chartDom.setOption(option);
        } else {
          console.error(`Invalid option object for ${optionType}`);
        }
      }
    },
    // 生成图表
    // domRef 图表标识 id
    // dataType 图表数据类型
    // optionType option类型
    // list 要生成图表的数据列表
    generateChart(domRef, dataType, optionType, list) {
      let chartInData = null;
      if (document.getElementById(domRef) || this.$refs[domRef]) {
        let chartDom = this.initChartDom(domRef);
        if (chartDom) {
          let chart = this.getChart(domRef);
          // 存在表格的话先进行销毁
          if (chart) chart.dispose();
          // 如果传入数据为空，则返回
          if (!list.length) return;
          // 如果list的子元素是数组
          const chartInData = Array.isArray(list[0])
            ? list.map((item) => this.generateChartInData(item))
            : this.generateChartInData(list);

          let data = this.chartDataFactory(dataType, chartInData);
          let option = this.getDefaultOption(optionType, data);
          if (option && typeof option === "object") {
            chartDom.setOption(option);
          }
        }
      }
    },

    // 生成图表
    // domRef 图表标识 id
    // dataType 图表数据类型
    // optionType option类型
    // list 要生成图表的数据列表
    generateChartWithCustomOption(
      domRef,
      dataType,
      optionType,
      list,
      customOption
    ) {
      let chartInData = null;
      if (document.getElementById(domRef) || this.$refs[domRef]) {
        let chartDom = this.initChartDom(domRef);
        if (chartDom) {
          let chart = this.getChart(domRef);
          // 存在表格的话先进行销毁
          if (chart) chart.dispose();
          // 如果传入数据为空，则返回
          if (list.length === 0) return;
          // 如果list的子元素是数组
          const chartInData = Array.isArray(list[0])
            ? list.map((item) => this.generateChartInData(item))
            : this.generateChartInData(list);

          let data = this.chartDataFactory(dataType, chartInData);
          let option = this.getCustomOption(optionType, data, customOption);
          if (option && typeof option === "object") {
            chartDom.setOption(option);
          }
        }
      }
    },

    getCanvas(item) {
      if (this.isDomSupported() && typeof item === "string") {
        item = document.getElementById(item) || this.$refs[item];
      } else if (item && item.length) {
        item = item[0];
      }
      if (item && item.canvas) {
        item = item.canvas;
      }
      return item;
    },

    // 获取图表
    getChart(key) {
      const canvas = this.getCanvas(key);
      return Object.values(this.instances)
        .filter((c) => c.canvas === canvas)
        .pop();
    },

    isDomSupported() {
      return typeof window !== "undefined" && typeof document !== "undefined";
    },

    // 初始化图表dom
    // 可以通过id和ref两种属性进行初始化
    initChartDom(domRef) {
      let chartDom = null;
      let initDom = document.getElementById(domRef) || this.$refs[domRef];

      chartDom = this.$echarts.init(initDom, null, {
        renderer: "canvas",
        useDirtyRect: false,
      });
      return chartDom;
    },

    // 生成图表数据
    chartDataFactory(dataType, chartInData) {
      let chartOutData = {};

      if (!["listData", "objectData"].includes(dataType)) {
        console.error("Invalid dataType");
      }

      switch (dataType) {
        case "listData":
          if (!Array.isArray(chartInData) || chartInData.length === 0) {
            console.error("Invalid chartInData");
          }

          let seriesList = [];
          chartInData.forEach((item) => {
            seriesList = [...seriesList, item[this.valueDataKey]];
          });
          chartOutData = {
            xAxisData: chartInData[0][this.nameDataKey],
            seriesData: seriesList,
          };
          break;

        case "objectData":
          chartOutData = {
            seriesData: this.generateObjectData(
              chartInData,
              this.nameDataKey,
              this.valueDataKey
            ),
          };
          break;
      }

      return chartOutData;
    },

    // 生成对象数据源
    // 属性为 name和value
    // chartInData  生成的图表数据
    // nameKey name对应的键
    // valueKey value对应的键
    generateObjectData(chartInData, nameKey, valueKey) {
      return chartInData[nameKey].map((name, i) => ({
        name,
        value: chartInData[valueKey][i],
      }));
    },

    // 生成图表需要的数据
    // list - 对象数组
    generateChartInData(list) {
      const chartInData = list.reduce(
        (acc, curr) => {
          Object.keys(curr).forEach((key) => {
            if (!acc[key]) {
              acc[key] = [];
            }
            acc[key].push(curr[key]);
          });
          return acc;
        },
        { length: list.length }
      );
      return chartInData;
    },

    // 配置好的默认option
    getDefaultOption(optionType, chartOutData) {
      let option = {};
      let seriesList = [];
      // 如果seriesData有数据，且seriesData的第一个元素是数组，说明传入的数据是多对象数组
      // 否则说明传入的是单个对象
      if (
        chartOutData.seriesData.length > 0 &&
        Array.isArray(chartOutData.seriesData[0])
      ) {
        seriesList = chartOutData.seriesData.map((item) => {
          return (item = {
            data: item,
          });
        });
      } else {
        seriesList = [
          {
            data: chartOutData.seriesData,
          },
        ];
      }

      switch (optionType) {
        case "lineOption":
          // 遍历后添加其他属性
          seriesList = seriesList.map((item) => {
            return (item = {
              data: item.data,
              type: "line",
            });
          });
          option = {
            title: {
              text: this.chartTitle,
            },
            xAxis: {
              type: "category",
              data: chartOutData.xAxisData,
            },
            yAxis: {
              type: "value",
            },
            series: seriesList,
          };
          break;
        case "barOption":
          seriesList = seriesList.map((item) => {
            return (item = {
              data: item.data,
              type: "bar",
            });
          });
          option = {
            xAxis: {
              type: "category",
              data: chartOutData.xAxisData,
            },
            yAxis: {
              type: "value",
            },
            series: seriesList,
          };
          break;
        case "pieOption":
          option = {
            title: {
              text: this.chartTitle,
              left: "center",
            },
            tooltip: {
              trigger: "item",
            },
            legend: {
              orient: "vertical",
              left: "left",
            },
            series: [
              {
                name: "Access From",
                type: "pie",
                radius: "50%",
                data: chartOutData.seriesData,
                emphasis: {
                  itemStyle: {
                    shadowBlur: 10,
                    shadowOffsetX: 0,
                    shadowColor: "rgba(0, 0, 0, 0.5)",
                  },
                },
              },
            ],
          };
          break;
      }

      return option;
    },

    // 由用户配置的自定义option
    getCustomOption(optionType, chartOutData, customOption) {
      let option = {};
      let seriesList = [];
      // 如果seriesData有数据，且seriesData的第一个元素是数组，说明传入的数据是多对象数组
      // 否则说明传入的是单个对象
      if (
        chartOutData.seriesData.length > 0 &&
        Array.isArray(chartOutData.seriesData[0])
      ) {
        seriesList = chartOutData.seriesData.map((item) => {
          return (item = {
            data: item,
          });
        });
      } else {
        seriesList = [
          {
            data: chartOutData.seriesData,
          },
        ];
      }
      switch (optionType) {
        case "lineOption":
        case "barOption":
          // 遍历后添加其他属性
          seriesList = seriesList.map((item) => {
            return (item = {
              data: item.data,
              type: customOption["type"],
            });
          });
          if (customOption["xAxis"]) {
            customOption["xAxis"]["data"] = chartOutData.xAxisData;
          }
          if (customOption["series"]) {
            customOption["series"] = seriesList;
          }
          break;
        case "pieOption":
          chartOutData.seriesData = chartOutData.seriesData.map(
            (item, index) => {
              item = {
                value: item.value > 0 ? item.value : null,
                name: item.name,
              };
              return item;
            }
          );
          if (customOption["series"]) {
            customOption["series"][0]["data"] = chartOutData.seriesData;
          }
          break;
      }
      option = customOption;
      return option;
    },
  },
};
</script>

<style>
</style>